extends TimeLord

const BLOCKSIZE=50
const SOURCESIZE=100
var BLOCKSCALE=float(BLOCKSIZE)/float(SOURCESIZE)
var VEC_BLOCK_SCALE=Vector2(BLOCKSCALE,BLOCKSCALE)
var BLOCKSX=20
var MAX_Y=5

#now i and j CAN be negative

var GROUND_LINE = 0

var Blocks=Array()

var Projections=Array()
var displacement = Array()

var wave_freq = 0.23
var wave_amplitude = BLOCKSIZE/2.3
var wave_k = 0.05
var time = 0

var BlockScene = load("res://Block.tscn")
var ProjectionScene = load("res://ProjectionBlock.tscn")

var PLAYER = null
var PLAYER_STARTPOS = Vector2(2, GROUND_LINE+1)

const TITLE_DISPLAY_TIME = 2

onready var MASTER_FADER = $"../MASTER_FADER"
onready var UBER_FADER = $"../UBER_FADER"
onready var BLURRER = $"../BLURRER"
onready var DIALOGUE_BOX = $"../DIALOGUE_BOX"

class Block_Bounding_Box:
	var min_i
	var max_i
	var min_j
	var max_j

## DATA

var current_level = 0

export var bonus = false

var bonus_level = Level.new(
	"NEVERENDING WINTER",
	"PLP's Happiness",
	["roll_right","roll_left"],
	Vector2(7,0),
	[
		Vector2(0,3),Vector2(1,4),Vector2(2,3),

		Vector2(3,1),Vector2(4,1),Vector2(5,1),Vector2(6,1),

		Vector2(7,3),Vector2(8,4),Vector2(9,3),

	],
	[
	],
	Dialogue.new([
		Saying.new(Saying.MYSELF,"I HAVE NO IDEA IF IT IS POSSIBLE"),
		Saying.new(Saying.MYSELF,"but i have a strong suspicion it is"),
		Saying.new(Saying.MYSELF,"rolls are disabled for this one"),
		Saying.new(Saying.MYSELF,"Don't forget to sleep!",true),
	]),
	Dialogue.new([
		Saying.new(Saying.PONY,"OMG YOU DID IT!. SHARE a video with me!",true),
	])
)

var Levels = [


Level.new(
	"April",
	"PLP's Junk",
	["plunge","drill","roll_right","roll_left"],
	Vector2(4,0),
	[],
	[
		Vector2(0,1),
		Vector2(0,2),
		Vector2(-2,3),Vector2(-1,3),Vector2(0,3),Vector2(1,3),Vector2(2,3),
		Vector2(-1,4),Vector2(0,4),Vector2(1,4),
		Vector2(0,5),
	],
	Dialogue.new([
		Saying.new(Saying.PONY,"Hi, How are you?",true),
		Saying.new(Saying.MYSELF,"Somewhat alive"),
		Saying.new(Saying.MYSELF,"thx for saving me and letting me stay"),
		Saying.new(Saying.PONY,"No biggie"),
		Saying.new(Saying.PONY,"Am I still triangle?"),
		Saying.new(Saying.MYSELF,"Yep you are."),
		Saying.new(Saying.PONY,"Am I at least pink?"),
		Saying.new(Saying.MYSELF,"Yep you are."),
		Saying.new(Saying.PONY,"Sorry for a loss of the part of your brain"),
		Saying.new(Saying.MYSELF,"Shit happens"),
		Saying.new(Saying.MYSELF,"Though i didn't expect such funny effects from an injury"),
		Saying.new(Saying.PONY,"...about your rent... i need your help with sth"),
		Saying.new(Saying.MYSELF,"What's it?'"),
		Saying.new(Saying.PONY,"just a bit of junk i need to get rid of"),
		Saying.new(Saying.PONY,"memories of first days here"),
		Saying.new(Saying.PONY,"make sure to clean everything above ground"),
		Saying.new(Saying.PONY,"(note that blocks directly overhead don't shift down)"),
	]),
	Dialogue.new([
		Saying.new(Saying.PONY,"Good Job!",true),
		Saying.new(Saying.MYSELF,"...cleaning junk on a island of junk..."),
	]),
	{"text": "WASD to move, E to erase layer. Erase everything except ground",
	"action": "erase_layer"}
),

Level.new(
	"May",
	"PLP's Art",
	["plunge","roll_right","roll_left"],
	Vector2(4,0),
	[
		Vector2(0,1),Vector2(1,1),Vector2(2,1),Vector2(3,1),
		Vector2(1,2),Vector2(2,2),Vector2(3,2),
		Vector2(2,3),Vector2(5,3),

		Vector2(3,4), Vector2(4,4),

	],
	[
		Vector2(0,1),Vector2(1,1),Vector2(2,1),Vector2(3,1),      Vector2(5,1),
		Vector2(1,2),Vector2(2,2),Vector2(3,2),                                Vector2(5,2),
		Vector2(2,3),Vector2(5,3),


		Vector2(2,4),
		Vector2(2,5),Vector2(3,5),Vector2(4,5),Vector2(5,5),
	],
	Dialogue.new([
		Saying.new(Saying.PONY,"Hi! Me again.",true),
		Saying.new(Saying.MYSELF,"Hi."),
		Saying.new(Saying.PONY,"Rent time! Let's go make some art!"),
		Saying.new(Saying.MYSELF,"hmmm"),
		Saying.new(Saying.PONY,"You will finish your fishing later, go, i have an inspiration"),
		Saying.new(Saying.PONY,"(pulsating blocks are in the right place, pink air should be filled)"),
	]),
	Dialogue.new([
		Saying.new(Saying.PONY,"Cool Wave, man!",true),
		Saying.new(Saying.MYSELF,"I thought it is a snake."),
		Saying.new(Saying.PONY,"It is junk. Like everything here"),
		Saying.new(Saying.PONY,"But one can still see things, so art matters"),
		Saying.new(Saying.PONY,"kinda cool"),
	]),
	{"text": "press X to drill down (any number of layers)",
	"action": "drill"}
),

Level.new(
	"June",
	"PLP's Smile",
	["roll_right","roll_left"],
	Vector2(5,0),
	[
		Vector2(0,2),

		Vector2(1,1),Vector2(2,1),Vector2(3,1),

		Vector2(4,2),

	],
	[
	],
	Dialogue.new([
		Saying.new(Saying.PONY,"Yo! WHAZZUP!",true),
		Saying.new(Saying.PONY,"Man these green pancakes of yours smell majestically"),
		Saying.new(Saying.PONY,"Can't believe you make them of seaweed"),
		Saying.new(Saying.MYSELF,"I will make it my proprietary secret"),
		Saying.new(Saying.MYSELF,"And some large corporation will buy it"),
		Saying.new(Saying.MYSELF,"Will be rich and have a lot of junk!",true),
		Saying.new(Saying.PONY,"That's the spirit!"),
		Saying.new(Saying.PONY,"If you have a lot of junk, you might even make an island from it"),
		Saying.new(Saying.PONY,"...that's what i did anyway...",true),
		Saying.new(Saying.PONY,"Let's go create sth cool!",true),
		Saying.new(Saying.MYSELF,"Ok-ok...*nom-nom-nom*... want some?"),
		Saying.new(Saying.PONY,"...I have 2 manipulators in my pony throat, man..."),
	]),
	Dialogue.new([
		Saying.new(Saying.PONY,"NEEEEAT",true),
		Saying.new(Saying.MYSELF,"So, how this junk flies exactly?"),
		Saying.new(Saying.PONY,"Junk is omnipotent"),
		Saying.new(Saying.PONY,"I myself was made from some electronic junk"),
		Saying.new(Saying.PONY,"And i can fly if i really want to"),
		Saying.new(Saying.PONY,"But now i just want to be a pony."),
		Saying.new(Saying.MYSELF,"Doesn't it make people omnipotent and not junk?..."),
	]),
	{"text": "press SPACE to hit junk (jump first, higher is wider, underwater possible)",
	"action": "plunge"}
),

Level.new(
	"July",
	"PLP's Sexuality",
	[],
	Vector2(5,0),
	[
		Vector2(2,1),Vector2(3,1),

		Vector2(0,-2), Vector2(1,-2), Vector2(2,-2),Vector2(3,-2),Vector2(4,-2),Vector2(5,-2),
		Vector2(0,-1), Vector2(2,-1),Vector2(3,-1),Vector2(5,-1),

	],
	[
	],
	Dialogue.new([
		Saying.new(Saying.PONY,"Hi, what are these floppies?",true),
		Saying.new(Saying.PONY,"Looks antique."),
		Saying.new(Saying.MYSELF,"Dug up an ancient computer for myself"),
		Saying.new(Saying.MYSELF,"Using it for math"),
		Saying.new(Saying.PONY,"New hobby?"),
		Saying.new(Saying.MYSELF,"No, old one"),
		Saying.new(Saying.MYSELF,"I was going to a remote island to complete my work"),
		Saying.new(Saying.MYSELF,"When that falling booster struck me"),
		Saying.new(Saying.PONY,"Glad i had you covered!"),
		Saying.new(Saying.MYSELF,"Thx a lot, man"),
		Saying.new(Saying.PONY,"Ohhh"),
		Saying.new(Saying.PONY,"I've already explained",true),
		Saying.new(Saying.PONY,"I'm not a man"),
		Saying.new(Saying.PONY,"I'm a Pink Lesbian Pony, PLP"),
		Saying.new(Saying.PONY,"If i wanted to be just a dude, i would made myself one",true),
		Saying.new(Saying.MYSELF,"ok-ok don't get mad"),
		Saying.new(Saying.PONY,"Too late! freedom of choice is important!"),
		Saying.new(Saying.PONY,"Your rent will be humiliating"),
	]),
	Dialogue.new([
		Saying.new(Saying.MYSELF,"Why is it so small?",true),
		Saying.new(Saying.PONY,"It has eggs dipped into the cold Bering Sea"),
	]),
	{"text": "F - roll underlying junk right, G - left. Earth state does not matter for level completion",
	"action": "roll_right"}

),

Level.new(
	"August",
	"PLP's Face",
	[],
	Vector2(4,0),
	[
		Vector2(0,1),Vector2(1,1),Vector2(2,1),
		Vector2(0,2),Vector2(1,2),Vector2(2,2), Vector2(3,2),Vector2(4,2),Vector2(5,2),
		Vector2(0,3),Vector2(1,3),Vector2(2,3), Vector2(3,3),Vector2(4,3),Vector2(5,3),
		Vector2(1,4),Vector2(2,4), Vector2(3,4),
		Vector2(2,5),
	],
	[],
	Dialogue.new([
		Saying.new(Saying.PONY,"Still after your generalized monstrous moonshine conjecture?",true),
		Saying.new(Saying.MYSELF,"Yea. Also after a regualr moonshine"),
		Saying.new(Saying.MYSELF,"Though seaweed is not the best substrate"),
		Saying.new(Saying.PONY,"I have sort of a present for you"),
	]),
	Dialogue.new([
		Saying.new(Saying.MYSELF,"So, you wanted me to see your face?",true),
		Saying.new(Saying.PONY,"Do you see it now?"),
		Saying.new(Saying.MYSELF,"Cubes sort of worked out"),
		Saying.new(Saying.MYSELF,"I wouldn't call it a present"),
		Saying.new(Saying.MYSELF,"It made me think though"),
		Saying.new(Saying.MYSELF,"If my condition is anything special at all"),
	])
),

Level.new(
	"September",
	"PLP's Earth",
	[],
	Vector2(0,0),
	make_earth(),
	[],
	Dialogue.new([
		Saying.new(Saying.MYSELF,"I have almost finished my work",true),
		Saying.new(Saying.MYSELF,"Will need to go soon"),
		Saying.new(Saying.PONY,"Cool! One last blast then?"),
	]),
	Dialogue.new([
		Saying.new(Saying.PONY,"This generalized monstrous moonshine problem you were chasing",true),
		Saying.new(Saying.PONY,"It is a big one, right?"),
		Saying.new(Saying.PONY,"I looked it up, you'll be super famous and everything"),
		Saying.new(Saying.PONY,"But you don't seem very excited"),
		Saying.new(Saying.MYSELF,"I sort of am and sort of not"),
		Saying.new(Saying.MYSELF,"I just thought..."),
		Saying.new(Saying.MYSELF,"if there is anything besides math and shapes at all",true),
		Saying.new(Saying.PONY,"Does it matter though?",true),
		Saying.new(Saying.PONY,"For me it is super-simple"),
		Saying.new(Saying.PONY,"Make junk. Play with junk"),
		Saying.new(Saying.PONY,"Junk is omnipotent. Junk can make you happy."),
		Saying.new(Saying.PONY,"****THE END***"),
	])
),

]

func make_earth(height = 3):
	var earth = Array()
	for i in range(BLOCKSX):
		earth.append(Vector2(i,height))
	return earth

class Level:
	var month
	var title
	var disabled = []
	var offset = Vector2()
	var blocks = []
	var solid_blocks = []
	var start_dialogue
	var end_dialogue
	var blinker_action = null

	func _init(_month="April",_title="PLP's Junk", _disabled = [], _offset=Vector2(0,0), _blocks= [Vector2(3,2)], _solids = [], _start = [], _end = [], _blinker_action = null):
		month = _month
		title = _title
		disabled = _disabled
		offset = _offset
		blocks = _blocks
		solid_blocks = _solids
		start_dialogue = _start
		end_dialogue = _end
		blinker_action = _blinker_action

## LIFECYCLE

func _init():
	randomize()
	for i in range (BLOCKSX):
		displacement.append(0)

func _ready():
	if bonus:
		Levels.clear()
		Levels.append(bonus_level)

	position = Vector2(BLOCKSIZE/2,get_viewport().size.y/2)
	prepare_current_level()
	PLAYER.listening = false

	MASTER_FADER.fade_out()
	UBER_FADER.visible = true
	var cl = Levels[current_level]
	UBER_FADER.make_title(cl.month,cl.title)
	execute_after(TITLE_DISPLAY_TIME,"after_level_title") # important to be at the end cause clear()

func after_level_title():
	MASTER_FADER.fade_in()
	execute_after(MASTER_FADER.FADE_ANITIME,"start_starting_dialogue")

func start_starting_dialogue():
	UBER_FADER.visible = false
	MASTER_FADER.fade_out()
	BLURRER.blur_in()

	DIALOGUE_BOX.start_dialogue(Levels[current_level].start_dialogue)
	DIALOGUE_BOX.connect("dialogue_ended",self,"prepare",[],CONNECT_ONESHOT)

func prepare():
	BLURRER.blur_out()
	PLAYER.listening = true
	var ba = Levels[current_level].blinker_action
	print(ba)
	if ba:
		var b = Blinker.new(ba["text"],ba["action"])
		add_child(b)

func start_ending_dialogue():
	PLAYER.listening = false
	BLURRER.blur_in()

	DIALOGUE_BOX.start_dialogue(Levels[current_level].end_dialogue)
	DIALOGUE_BOX.connect("dialogue_ended",self,"next_level",[],CONNECT_ONESHOT)

func next_level():
	MASTER_FADER.fade_in()
	current_level+=1
	if current_level == len(Levels):
		execute_after(MASTER_FADER.FADE_ANITIME,"WIN_GAME")
	else:
		execute_after(MASTER_FADER.FADE_ANITIME,"_ready")

func WIN_GAME():
	get_tree().change_scene("res://END.tscn")

func clear():
	$Projection_Timer.stop()

	for c in get_children():
		if c != $Projection_Timer:
			c.queue_free()
	for l in [Projections,Blocks]:
		l.clear()
	if PLAYER:
		PLAYER.queue_free()
	PLAYER = null

func prepare_current_level():
	clear()
	init_blocks()
	init_projections()
	PLAYER = spawn_Player(PLAYER_STARTPOS.x, PLAYER_STARTPOS.y)
	$Projection_Timer.start()

func _process(delta):
	time+=delta
	var time_phase = time*wave_freq*2*PI
	for i in range (len(displacement)):
		var spatial_phase = i*wave_k*2*PI
		displacement[i] = sin(time_phase+spatial_phase)*wave_amplitude


func check_height():
	for b in Blocks:
		if floor(abs(b._j)) > MAX_Y:
			print("reset triggered at _j", b._j)
			onscreen_reset()
			var warn = WarningSign.new("TOO HIGH. I HATE IT!", 1.0)
			add_child(warn)

func init_blocks():
	for i in range (BLOCKSX):
		add_trash(i,GROUND_LINE)

	var l = Levels[current_level]
	for v in l.solid_blocks:
		add_trash(l.offset.x+v.x,l.offset.y+v.y)

func init_projections():
	var level = Levels[current_level]
	for b in level.blocks:
		add_projection(level.offset.x+b.x,level.offset.y+b.y)


func onscreen_reset():
	var list = Blocks.duplicate()
	for b in list:
		b.erase()
	PLAYER.move_to(PLAYER_STARTPOS.x,PLAYER_STARTPOS.y)
	patch_ground_hole(0,BLOCKSX-1)
	make_n_roll_level_blocks()
	pass

func make_n_roll_level_blocks():
	var l = Levels[current_level]
	var targets = Array()
	for v in l.solid_blocks:
		var b = add_trash(l.offset.x+v.x - BLOCKSX,l.offset.y+v.y)
		targets.append(b)
	translate_block(targets,BLOCKSX,0)

## INTERFACE

### Variety of blocks

func new_projection():
	var block = ProjectionScene.instance()
	return block

func add_projection(i,j):
	var block = new_projection()
	block_setup(block, i, j)
	Projections.append(block)
	return block

func new_trash_block():
	var block = BlockScene.instance()
	var color = Color8(randi() % 256, randi() % 256, randi() % 256,255)
	block.color = color.darkened(0.5)
	return block


func add_trash(i,j):
	var block = new_trash_block()
	spawn_physical_block(block,i,j)
	return block

func new_Player():
	var block = BlockScene.instance()
	block.set_script(load("res://scripts/Player.gd"))
	return block

func spawn_Player(i,j):
	var block = new_Player()
	block_setup(block, i, j)
	return block

func spawn_physical_block(block,i,j):
	Blocks.append(block)
	block_setup(block, i, j)

func block_setup(block,i,j):
	add_child(block)
	block._i=i
	block._j=j
	block.scale = VEC_BLOCK_SCALE

### Grid Interface

func get_block(i,j):
	for b in Blocks:
		if b._i==i and b._j==j:
			return b
	return null

func get_bb(array):
	if len(array) == 0:
		return null
	var i_array = Array()
	var j_array = Array()
	for b in array:
		i_array.append(b._i)
		j_array.append(b._j)
	var bb = Block_Bounding_Box.new()

	bb.max_i = i_array.max()
	bb.min_i = i_array.min()

	bb.max_j = j_array.max()
	bb.min_j = j_array.min()
	return bb

func patch_ground_hole(i_min,i_max, delay=0):
	print ("patching ground hole", i_min, i_max)

	var targets = Array()
	var gap_width = i_max-i_min+1

	for n in range(gap_width):
		var new_block = add_trash(-n-1,GROUND_LINE)
		targets.append(new_block)
	for i in range(i_min):
		var block = get_block(i,GROUND_LINE)
		if block:
			targets.append(block)

	translate_block(targets,gap_width,0,delay)

func translate_block(array, i_trans, j_trans, delay=0, time = Block.BLOCK_MOVE_ANITIME):
	for b in array:
		if b:
			b.move_to(b._i+i_trans,b._j+j_trans, delay, time)


func check_x_continuity(i,j,direction):
	var continuous_num = 0
	while(true):
		var ii = i + continuous_num*sign(direction)
		if (not get_block(ii,j)) or (not ii in range(BLOCKSX)) :
			break
		else:
			continuous_num+=1
	return continuous_num-1

### Projection work

func _on_Projection_Timer_timeout():
	var complete = true
	var projection_coords = Array()

	for p in Projections:
		if not p.check_completed():
			complete = false
		projection_coords.append(Vector2(p._i,p._j))

	for b in Blocks:
		if not Vector2(b._i,b._j) in projection_coords:
			if b._j != GROUND_LINE:
				complete = false

	if complete:
		win_stage()

func win_stage():
	if PLAYER.listening:
		print ("you won the stage!")
		start_ending_dialogue()
		pass
